import { v4 } from 'uuid'
import CryptoJS from 'crypto-js'
const { indexedDB, mozIndexedDB, webkitIndexedDB, msIndexedDB } = window
const WebDB = indexedDB || mozIndexedDB || webkitIndexedDB || msIndexedDB

// 设置内置key和iv
// 用来加密非敏感数据
const aesKey = '77031bd5-d101-42ee-9307-4a2146b22a14'

// TODO 设置秘钥和偏移量
export const Assemble = async (uuid) => {
    const combination = (data) => {
        const [A01, A02, A03, A04, A05] = data.split('-')
        const key = A05.split('').reverse().join('') + A03
        const iv = A04 + A01.split('').reverse().join('') + A02
        return { key, iv }
    }
    return new Promise(res => {
        const { key, iv } = combination(uuid || aesKey)
        res({ key: CryptoJS.enc.Utf8.parse(key), iv: CryptoJS.enc.Utf8.parse(iv) })
    })
}

// TODO 加密
export const Encrypt = async (word, uuid) => {
    const { key, iv } = await Assemble(uuid)
    const data = typeof (word) === 'object' ? JSON.stringify(word) : word
    let srcs = CryptoJS.enc.Utf8.parse(data)
    let encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 })
    return encrypted.ciphertext.toString().toUpperCase()
}

// TODO 解密
export const Decrypt = async (word, uuid) => {
    const { key, iv } = await Assemble(uuid)
    let encryptedHexStr = CryptoJS.enc.Hex.parse(word)
    let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr)
    let decrypt = CryptoJS.AES.decrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 })
    let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
    const data = decryptedStr.toString() ? JSON.parse(decryptedStr.toString()) : decryptedStr.toString()
    return data
}

// TODO 置换加密数据
export const PermutationData = async (e) => {
    const { secretData, secretKey } = e
    const uuid = await Decrypt(secretKey)
    const dec = await Decrypt(secretData, uuid)
    return dec
}

// TODO 创建加密信息
export const EncryptedData = async (e) => {
    const uuid = v4()
    const key = await Encrypt(uuid)
    const parame = await Encrypt(e, uuid)
    return { secretKey: key, secretData: parame }
}


// TODO 打开数据库
export const IndexedDBFun = () => {
    return new Promise(res => {
        const request = WebDB.open('webDB', 1)
        request.onsuccess = e => res(e.target.result)
        request.onerror = e => console.error('[DBError]', e)
        request.onupgradeneeded = e => e.target.result.createObjectStore("ClientData", { keyPath: "uuid" })
    })
}

// TODO 清空缓存信息
export const IndexedDBResetting = () => {
    if (window.webDB) {
        window.webDB.then(db => db.transaction('ClientData', "readwrite").objectStore('ClientData').clear())
    } else setTimeout(IndexedDBResetting, 500)
}

// TODO 添加主键数据
export const AddIndexdDB = async (key, data) => {
    const json = { uuid: await Encrypt(key), data: await Encrypt(data) }
    return new Promise(res => {
        window.webDB.then(db => {
            const rest = db.transaction(['ClientData'], 'readwrite').objectStore('ClientData').add(json)
            rest.onsuccess = () => res()
            rest.onerror = e => { console.log('[数据更新失败!]', e) }
        })
    })
}

// TODO 更新主键(uuid)数据
export const PutIndexedDB = async (key, data) => {
    const json = { uuid: await Encrypt(key), data: await Encrypt(data) }
    return new Promise(res => {
        window.webDB.then(db => {
            const rest = db.transaction(['ClientData'], 'readwrite').objectStore('ClientData').put(json)
            rest.onsuccess = () => res()
            rest.onerror = e => { console.log('[数据更新失败!]', e) }
        })
    })
}

// TODO 获取主键(uuid)解密数据
export const GetIndexedDB = async (key) => {
    return new Promise(res => {
        window.webDB.then(async db => {
            const get = await Encrypt(key)
            const rest = db.transaction(['ClientData']).objectStore('ClientData').get(get)
            rest.onsuccess = async e => {
                const { result } = e.target
                if (result) res(await Decrypt(result.data))
                else res()
            }
            rest.onerror = e => { console.log('[获取数据失败!]', e) }
        })
    })
}



